package action

import (
	"net/http"
	"workspace/websocket/src/global"

	"encoding/json"

	"time"

	"github.com/gorilla/websocket"
)

//调度器结构体
type Dispatcher struct {
	Clients      map[*Client]bool //客户端池
	addClient    chan *Client     //要添加到池的客户端
	removeClient chan *Client     //要从池删除的客户端
}

//实例化调度器
func NewDispatcher() *Dispatcher {
	//设置并赋值websocket服务端对象
	Upgrader = websocket.Upgrader{
		//检查origin
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	//返回一个新的调度器
	return &Dispatcher{
		Clients:      make(map[*Client]bool),
		addClient:    make(chan *Client),
		removeClient: make(chan *Client),
	}
}

//调度器启动
func (dispatcher *Dispatcher) Start() {
	//在一个独立的协程里阻塞运行
	go func() {
		for {
			//使用select处理Dispatcher中的三个通道数据
			select {
			//如果有要添加到池的客户端
			case conn := <-dispatcher.addClient:
				dispatcher.Clients[conn] = true //将连接池中的连接的值改为空，表示还没有订阅消息频道
				global.Logger.Debug("websocket客户端已加入到调度器")
			//如果有要从池中删除的客户端
			case conn := <-dispatcher.removeClient:
				if _, ok := dispatcher.Clients[conn]; ok { //如果客户端否存在池中
					delete(dispatcher.Clients, conn) //从池中删除当前客户端
					close(conn.sendData)             //关闭客户端连接的发送消息通道
					global.Logger.Debug("websocket客户端断开连接并从调度器中删除")
				}
			}
		}
	}()
}

//广播
func (dispatcher *Dispatcher) Broadcast(data []byte) {
	global.Logger.Debug(string(data))
	//return

	//解析data成map
	jsonData := make(map[string]interface{})
	err := json.Unmarshal(data, &jsonData)
	if err != nil {
		global.Logger.Error(err.Error())
		return
	}
	//遍历池中所有的客户端
	for client := range dispatcher.Clients {
		if len(client.topics) == 0 {
			return
		}
		//生成一个map，用于发给客户端
		sendData := make(map[string]interface{})
		sendData["time"] = time.Now().Unix()            //发送时间
		sendData["data"] = make(map[string]interface{}) //内容数据
		//遍历每个客户端的订阅
		price := make(map[string]interface{})
		for _, v := range client.topics {
			price[v] = jsonData[v]
		}
		sendData["data"] = price
		//将map序列化成json
		sendDataJSON, err := json.Marshal(sendData)
		if err != nil {
			global.Logger.Error(err.Error())
			return
		}
		//将json数据推入客户端的消息发送通道
		client.sendData <- sendDataJSON
	}
}
